package sk.fiit.lulco.gui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;

import sk.fiit.lulco.grafy.NewHEALAlgorithm;

public class GraphWindow extends JFrame implements GraphListener {

	private static final long serialVersionUID = 518563109075068075L;
	private List<JMenuItem> menuItems = new ArrayList<JMenuItem>();
	private JMenuItem cancel;

	private JProgressBar progress;
	private GraphPanel graphPanel;
	private JTextArea console;

	private Settings settings = new Settings();
	private GraphThread thread;

	public GraphWindow() {
		super("Graph coloring");
		setLocation(300, 200);
		setPreferredSize(new Dimension(900, 600));
		setVisible(true);
		addWindowListener(new WindowAdapter() {

			@Override
			public void windowClosing(WindowEvent e) {
				super.windowClosing(e);
				exitPerformed();
			}
		});
		initLayout();
		
		pack();
	}

	private void initLayout() {
		initMenu();
		setLayout(new BorderLayout(3, 3));

		graphPanel = new GraphPanel();
		graphPanel.setPreferredSize(new Dimension(600, 600));
		graphPanel.setSize(new Dimension(600, 600));

		console = new JTextArea();
		JScrollPane scroll = new JScrollPane(console);
		scroll.setPreferredSize(new Dimension(400, 600));
		scroll.setSize(new Dimension(400, 600));

		console.setEditable(false);
		JSplitPane main = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, graphPanel, scroll);
		main.setOneTouchExpandable(true);
		main.setDividerLocation(500);
		add(main, BorderLayout.CENTER);

		progress = new JProgressBar();
		add(progress, BorderLayout.SOUTH);		
	}

	private void initMenu() {
		JMenuBar menuBar = new JMenuBar();
		setJMenuBar(menuBar);

		JMenu file = new JMenu("File");
		menuBar.add(file);

		menuItems.clear();
		JMenuItem item = null;
		for (GraphItem graph : GraphItem.values()) {
			final GraphItem a = graph;
			item = new JMenuItem(graph.getMenuName());
			item.addActionListener(new ActionListener() {

				@Override
				public void actionPerformed(ActionEvent evt) {
					runGraphPerformed(a);
				}
			});
			file.add(item);
			menuItems.add(item);
		}

		file.addSeparator();
		cancel = new JMenuItem("Cancel");
		file.add(cancel);
		cancel.setEnabled(false);
		cancel.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent evt) {
				cancelPerformed();
			}
		});

		file.addSeparator();
		JMenuItem clear = new JMenuItem("Clear console");
		file.add(clear);
		clear.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				if (console != null) {
					console.setText("");
				}
			}
		});

		file.addSeparator();
		JMenuItem exit = new JMenuItem("Exit");
		exit.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				exitPerformed();
			}
		});
		file.add(exit);

		JMenu edit = new JMenu("Edit");
		menuBar.add(edit);

		JMenuItem settings = new JMenuItem("Settings");
		edit.add(settings);
		settings.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				new SettingsWindow(GraphWindow.this, GraphWindow.this.settings);				
			}
		});
	}

	private void runGraphPerformed(GraphItem item) {
		setMenuEnabled(false);
		cancel.setEnabled(true);

		thread = new NewHEALAlgorithm(item);
		thread.setListener(this);
		new Thread(thread).start();
	}

	private void cancelPerformed() {
		if (thread != null) {
			thread.cancel();
		}
		// setMenuEnabled(true);
		// cancel.setEnabled(false);
	}

	private void exitPerformed() {
		if (thread != null) {
			thread.cancel();
		}
		dispose();
	}

	private void setMenuEnabled(boolean enabled) {
		for (JMenuItem item : menuItems) {
			item.setEnabled(enabled);
		}
	}

	@Override
	public void onFinish() {
		setMenuEnabled(true);
		cancel.setEnabled(false);
	}

	@Override
	public void onGraphEvent(GraphEvent evt) {
		if (graphPanel != null) {
			graphPanel.setGraph(evt.getGraph());
			graphPanel.repaint();
		}

		progress.setMaximum(evt.getGenerationCount());
		progress.setValue(evt.getActualGeneration());
	}

	@Override
	public void onTextAppend(String text) {
		DateFormat format = new SimpleDateFormat("HH:mm:ss.SSS");
		console.append(format.format(new Date(System.currentTimeMillis())));
		console.append("\n");
		console.append(text);
		console.append("\n");
		console.setCaretPosition(console.getText().length());
	}

	@Override
	public void onError(String message) {
		DateFormat format = new SimpleDateFormat("HH:mm:ss.SSS");
		console.append(format.format(new Date(System.currentTimeMillis())));
		console.append(" ERROR:\n");
		console.append(message);
		console.append("\n");
		console.setCaretPosition(console.getText().length());
		cancelPerformed();
	}
}
